package com.pallass.config;

import java.sql.SQLException;
import java.util.Properties;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
@PropertySource("classpath:jdbc.properties")
public class JpaConfiguration {

	private static Logger logger = LoggerFactory.getLogger(JpaConfiguration.class);

	@Resource
	private Environment environment;

	@Value("${jdbc.driverClassName}")
	private String driverClassName;
	@Value("${jdbc.url}")
	private String url;
	@Value("${jdbc.username}")
	private String username;
	@Value("${jdbc.password}")
	private String password;

	public DataSource basicDataSource() {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setDriverClassName(driverClassName);
		dataSource.setUrl(url);
		dataSource.setUsername(username);
		dataSource.setPassword(password);
		return dataSource;
	}

	@Bean(initMethod = "init", destroyMethod = "close")
	DruidDataSource dataSource() {
		DruidDataSource druidDataSource = new DruidDataSource();

		druidDataSource.setDriverClassName(driverClassName);
		druidDataSource.setUrl(url);
		druidDataSource.setUsername(username);
		druidDataSource.setPassword(password);

		// 初始化连接大小
		druidDataSource.setInitialSize(1);
		// 连接池最大使用连接数量
		druidDataSource.setMaxActive(20);
		// 连接池最小空闲
		druidDataSource.setMinIdle(1);

		// 获取连接最大等待时间
		druidDataSource.setMaxWait(60000);//

		// 打开removeAbandoned功能
		druidDataSource.setRemoveAbandoned(true);
		// 单位: 秒
		druidDataSource.setRemoveAbandonedTimeout(1800);
		// 关闭abanded连接时输出错误日志
		druidDataSource.setLogAbandoned(true);

		// 间隔多久才进行一次检测，检测需要关闭的空闲连接，单位: 毫秒
		druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
		// 一个连接在池中最小生存的时间，单位: 毫秒
		druidDataSource.setMinEvictableIdleTimeMillis(25200000);

		druidDataSource.setValidationQuery("SELECT 1");
		druidDataSource.setTestOnBorrow(false);
		druidDataSource.setTestOnReturn(false);
		druidDataSource.setTestWhileIdle(true);

		// 打开PSCache，并且指定每个连接上PSCache的大小
		druidDataSource.setPoolPreparedStatements(true);
		druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(20);

		// 监控数据库, 配置监控统计拦截的filters，去掉后监控界面sql无法统计
		try {
			druidDataSource.setFilters("stat, wall");
		} catch (SQLException e) {
			logger.debug("Set druid filter stat and wall failure.");
		}

		return druidDataSource;
	}

	@Bean
	Properties jpaProperties() {
		Properties jpaProperties = new Properties();
		jpaProperties.put("hibernate.query.substitutions", "true 1, false 0");
		jpaProperties.put("hibernate.default_batch_fetch_size", 16);
		jpaProperties.put("hibernate.max_fetch_depth", 2);
		jpaProperties.put("hibernate.generate_statistics", true);
		jpaProperties.put("hibernate.bytecode.use_reflection_optimizer", true);
		jpaProperties.put("hibernate.cache.use_second_level_cache", false);
		jpaProperties.put("hibernate.cache.use_query_cache", false);
		jpaProperties.put("hibernate.format_sql", true);
		return jpaProperties;
	}

	@Bean
	public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

		HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
		jpaVendorAdapter.setGenerateDdl(true);
		jpaVendorAdapter.setShowSql(true);
		jpaVendorAdapter.setDatabase(Database.MYSQL);
		jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");

		HibernatePersistenceProvider persistenceProvider = new HibernatePersistenceProvider();

		HibernateJpaDialect jpaDialect = new HibernateJpaDialect();

		LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();

		factory.setDataSource(dataSource());
		factory.setPersistenceProvider(persistenceProvider);
		factory.setJpaVendorAdapter(jpaVendorAdapter);
		factory.setPackagesToScan("com.pallass.admin.domain", "com.pallass.organization.domain");

		factory.setJpaProperties(jpaProperties());
		factory.setJpaDialect(jpaDialect);

		factory.afterPropertiesSet();

		return factory;
	}

	/**
	 * 事务管理器
	 * 
	 * @return
	 */
	@Bean
	public PlatformTransactionManager transactionManager() {
		JpaTransactionManager transactionManager = new JpaTransactionManager();
		transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
		return transactionManager;
	}

}
